<?php

	final class SmRoot0v0r01_Session extends _smuoiDbRowExtended implements SmRoot_Session{
		
		protected $table = 'sessions';
		
		private $update_time, $usr, $flag_ok;
		
		function __construct($id, $pkg, $data=false, $usr=false){
			if(!$id && !$data){
				if((!($usr instanceof SmRoot_User))||(!$usr->ok())) trigger_error('No valid sibling!', E_USER_ERROR);
				$this->usr = $usr;
				return parent::__construct($id, $pkg, $data, 1);
			}
			parent::__construct($id, $pkg, $data, 1);
			if(!$this->usr = $pkg->db->get($this->data->usr)) trigger_error("Session user '$this->data->usr' invalid", E_USER_ERROR);
			if(!$this->flag_ok = $this->check_validity()) return;
			$this->usr->continue_session($this);
			$this->put_pubkey();
		}
		
		protected function initialize(){
			$data = array(
				'usr' => $this->usr->id,
				'kooky' => rand_string(42),
				'pubkey' => INSTANCE,
				'ip' => $_SERVER['REMOTE_ADDR'],
				'u_agent' => $_SERVER['HTTP_USER_AGENT']
			);
			$data['time_in'] = $data['last_req'] = floor(SMUOI_TIME_IN);
			$data['expires'] = $data['time_in'] + 3600;
			$data['sudo_x'] = (($this->usr instanceof SmRoot_Sudoer)&&($this->usr->sudo_flagged())) ? $data['expires'] : 0;
			parent::initialize($data);
			$this->flag_ok = true;
		}
		
		function ok(){
			return $this->flag_ok;	
		}
		
		function usr(){
			return $this->usr;	
		}
		
		function usr_reset($usr){
			if(($usr !== $this->usr)||(!$usr->ok())) return;
			$x = floor($this->update_time)+3600;
			$this->hard_set('expires', $x);
			if((!$usr instanceof SmRoot_Sudoer)||(!$usr->sudo_flagged())) return;
			$this->hard_set('sudo_x', $x);
		}
		
		// This is a mess cos we can't call will_permit in the public domain
		private function check_validity(){
			$d = PUBLIC_DOMAIN ? true : sm_cwdom()->will_permit($this->usr);
			$x = ($this->data->expires > time());
			if($d && $x){	
				if(!PUBLIC_DOMAIN) $this->update();
				return true;
			}
			$this->destroy();
			if(!$d) trigger_error("403 INVALID SESSION", E_USER_ERROR);
			return false;
		}
		
		function kooky(){
			if($this->data_age() > 1){
				$d = $this->pkg->al()->select('kooky', $this->table(), array('id'=>$this->id));
				// If fail (session destroyed elsewhere), just send old kooky for simplicity
				if($d) $this->data->kooky = $d[0]['kooky'];
				$this->update_time = utime();
			}
			return $this->data->kooky;
		}
		
		private function data_age(){
			return (utime() - $this->update_time);
		}
		
		private function update(){
			if(DOUPLOAD || PUBLIC_DOMAIN) return;
			$time = floor($this->update_time);
			$this->edits['last_req'] = floor(SMUOI_TIME_IN);
			if(($this->data->last_req + 30) < $time){
				// update session expiry time
				$this->hard_set('expires', $time+3600);
				$this->hard_set('kooky', rand_string(42));
			}
			if(($this->usr instanceof SmRoot_Sudoer)&&($this->usr->sudo_flagged())) $this->hard_set('sudo_x', $this->data->ses_expires);
			$this->commit();
		}
		
		private function put_pubkey(){
			setcookie('pubkey', $this->data->pubkey, $this->data->expires, '/', SERVER_NAME);
		}

		function commit(){
			parent::commit(1);
			$this->update_time = utime();
		}
		
		function auxiliary_data(){
			return new objRsrc(Cache::pathto($this->cache_file()), 'w', 1);	
		}
		
		private function cache_file(){
			Cache::tsinit('/sessions/');
			return '/sessions/'.alphanum($this->id);
		}
		
		function destroy(){
			Cache::delete($this->cache_file());
			return $this->pkg->al()->delete($this->table(), array('id'=>$this->id));
		}
		
	}

?>
